package com.qf.search.service.Impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.search.service.SearchService;
import com.qf.search.utils.SearchUtil;
import com.qianfeng.smsplatform.common.model.Standard_Report;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 徐老板
 * @date 2020/3/3   15:18
 */
@Service
public class SearchServiceImpl implements SearchService {

    //es依赖包提供这个工具类
    //client在这里相当于提交的意思
    @Resource
    RestHighLevelClient client;
    @Resource
    private ObjectMapper objectMapper;


    @Value("${spring.data.elasticsearch.index.name}")
    private String index;

    @Value("${spring.data.elasticsearch.index.type}")
    private String type;

    @Override
    public void createIndex() throws Exception {
        if (!existsIndex(index)){
            //不存在就可以创建
            CreateIndexRequest createIndexRequest=new CreateIndexRequest(index);
            SearchUtil.buildingSetting(createIndexRequest);
            SearchUtil.buildingMapping(createIndexRequest, type);
            //这个地方不抛异常证明 是创建成功的
            CreateIndexResponse response = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);

        }else {
            //已经存在
        }

    }

    @Override
    public void deleteIndex(String index) throws Exception {

    }

    @Override
    public void addIndex(String json) throws Exception {
        IndexRequest indexRequest=new IndexRequest(index,type);
        indexRequest.source(json, XContentType.JSON);
        IndexResponse index = client.index(indexRequest, RequestOptions.DEFAULT);
        //这个是添加操作 正常会把返回值打印出来 这里就不打印了


    }

    @Override
    public void updateIndex(Standard_Report report) throws Exception {

    }

    @Override
    public boolean existsIndex(String index) throws Exception {
        GetIndexRequest getRequest=new GetIndexRequest();
        getRequest.indices(index);
        boolean exists = client.indices().exists(getRequest, RequestOptions.DEFAULT);
        return exists;
    }

    @Override
    public List<Map> search(String params) throws Exception {
        List<Map> result = new ArrayList<>();
        Map paramMap =null;
        //这里首先对传过来的参数进行非空校验
        if (params==null){
            paramMap = new HashMap();

        }else {
            paramMap = objectMapper.readValue(params, Map.class);
        }
        //接下来查数据  这里提供的方法允许用户以各种条件查询 所以我们要判断各种条件来源的方式
        SearchSourceBuilder searchSourceBuilder =SearchUtil.builderSearchSource(paramMap);

        //接下来的内容纯手打
        //首先这里从es查到的数据会有分页的问题 如果前端没有传过来相关参数 这里要设置默认参数
        Integer start = (Integer) paramMap.get("start");
        Integer rows = (Integer) paramMap.get("rows");
        searchSourceBuilder.from(start == null ? 0 : start);
        searchSourceBuilder.from(rows == null ? 20 : rows);
        //接下来高亮设置 这里假设用户要求高亮显示
        String keyword = (String) paramMap.get("keyword");
       //然后进行非空校验
        if (!StringUtils.isEmpty(keyword)){
            //这个参数代表用户传递的关键词 我们需要返回高亮数据
            String highLightPreTag = (String) paramMap.get("highLightPreTag");
            String highLightPostTag = (String) paramMap.get("highLightPostTag");
            HighlightBuilder highlightBuilder=new HighlightBuilder();
            //这个如果多个字段设置为高亮 那么需要设置为false  这里做了一个高亮设置
            highlightBuilder.requireFieldMatch(false).field("messageContent").preTags(highLightPreTag).postTags(highLightPostTag);
            //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
            highlightBuilder.fragmentSize(1000);//最大高亮分片数
            highlightBuilder.numOfFragments(0);//从第一个分片获取高亮片段
            searchSourceBuilder.highlighter(highlightBuilder);
        }
        //这个是创建搜索请求对象 client端对这个进行操作的
        SearchRequest searchRequest = new SearchRequest(index);
        searchRequest.source(searchSourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits responseHits = response.getHits();
        //获取数据总条数
        long totalHits = responseHits.getTotalHits();
        //获取所有数据内容
        SearchHit[] hits = responseHits.getHits();
        for (SearchHit hit : hits) {
            //获取结果的map 还有一个方法是获取json字符串的
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            //接下来处理高亮数据
            if (!StringUtils.isEmpty(keyword)){
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField highlight = highlightFields.get("messageContent");
                if (highlight!=null){
                    //这个是设置高亮之后的数据  这个是获取高亮的片段 终于推导出来了
                    Text[] fragments = highlight.fragments();
                    if (fragments != null) {
                        Text text = fragments[0];//获取到具体的高亮数据了
                        //需要将上面 map 中的原始内容替换为高亮内容
                        sourceAsMap.put("messageContent", text.toString());
                    }
                }

            }

            result.add(sourceAsMap);//保存到集合
        }

        System.err.println(result.size());
        return result;
    }

    @Override
    public long count(String params) throws Exception {

      //这一步直接从上面复制下来
        List<Map> result = new ArrayList<>();
        Map paramMap =null;
        //这里首先对传过来的参数进行非空校验
        if (params==null){
            paramMap = new HashMap();

        }else {
            paramMap = objectMapper.readValue(params, Map.class);
        }
        //接下来查数据  这里提供的方法允许用户以各种条件查询 所以我们要判断各种条件来源的方式
        SearchSourceBuilder searchSourceBuilder =SearchUtil.builderSearchSource(paramMap);
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = search.getHits();
        long totalHits = hits.getTotalHits();


        return totalHits;
    }
    //接下来写controller层 提供供外部调用的路径

}
